package hu.bme.aut.consulttime.server.entityservices;

import hu.bme.aut.consulttime.client.ProjectService;
import hu.bme.aut.consulttime.entitydtos.ProjectDTO;
import hu.bme.aut.consulttime.entitydtos.UserDTO;
import hu.bme.aut.consulttime.server.entities.Project;
import hu.bme.aut.consulttime.server.entities.Tutor;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.TypedQuery;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class ProjectServiceImpl extends RemoteServiceServlet implements
		ProjectService {

	private static final long serialVersionUID = -7770979490757180511L;

	public static final EntityManager entityManager() {
		return EntityManagerFactoryWrapper.get().createEntityManager();
	}

	@Override
	public Boolean createProject(ProjectDTO projectDTO) {
		EntityManager em = entityManager();
		EntityTransaction tx = em.getTransaction();

		Project project = new Project();
		project.setTitle(projectDTO.getTitle());
		project.setDescription(projectDTO.getDescription());
		project.setType(projectDTO.getType());

		// Add tutors to Project
		List<Tutor> tutors = new ArrayList<Tutor>();
		for (UserDTO tmp : projectDTO.getTutors()) {
			Tutor tutor = em.find(Tutor.class, tmp.getUserId());
			if (tutor != null) {
				tutors.add(tutor);
			}
		}
		project.setTutors(tutors);

		try {
			tx.begin();
			em.persist(project);
			tx.commit();
			return true;
		} catch (Throwable t) {
			t.printStackTrace();
			tx.rollback();
			return false;
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	@Override
	public List<UserDTO> retrieveTutors() {
		EntityManager em = entityManager();
		List<Tutor> tutors = null;

		try {
			TypedQuery<Tutor> query = em.createQuery("select s from Tutor s",
					Tutor.class);
			tutors = query.getResultList();
		} finally {
			em.close();
		}

		List<UserDTO> userDTOs = new ArrayList<UserDTO>();
		for (Tutor tmp : tutors) {
			UserDTO tutor = new UserDTO();
			tutor.setUserId(tmp.getUserId());
			tutor.setUserName(tmp.getUserName());
			tutor.setEmail(tmp.getEmail());
			tutor.setEmailNotification(tmp.isEmailNotification());
			tutor.setFirstName(tmp.getFirstName());
			tutor.setLastName(tmp.getLastName());
			userDTOs.add(tutor);
		}

		return userDTOs;
	}

	@Override
	public List<ProjectDTO> retrieveProjects() {
		EntityManager em = entityManager();
		List<Project> projects = null;

		try {
			TypedQuery<Project> query = em.createQuery(
					"select s from Project s", Project.class);
			projects = query.getResultList();
		} finally {
			em.close();
		}

		List<ProjectDTO> projectDTOs = new ArrayList<ProjectDTO>();
		for (Project tmp : projects) {
			ProjectDTO project = new ProjectDTO();
			project.setTitle(tmp.getTitle());
			project.setType(tmp.getType());
			project.setDescription(tmp.getDescription());
			project.setProjectId(tmp.getProjectId());

			// Add Tutors
			project.setTutors(retrieveTutors(tmp.getProjectId()));

			projectDTOs.add(project);
		}

		return projectDTOs;
	}
	
	@Override
	public List<ProjectDTO> retrieveProjects(long tutorId) {
		EntityManager em = entityManager();
		List<Project> projects = null;

		try {
			Tutor tutor = em.find(Tutor.class, tutorId);
			
			TypedQuery<Project> query = em.createQuery(
					"select p from Project p where ?1 member of p.tutors", Project.class);
			query.setParameter(1, tutor);
			projects = query.getResultList();
		} finally {
			em.close();
		}

		List<ProjectDTO> projectDTOs = new ArrayList<ProjectDTO>();
		for (Project tmp : projects) {
			ProjectDTO project = new ProjectDTO();
			project.setTitle(tmp.getTitle());
			project.setType(tmp.getType());
			project.setDescription(tmp.getDescription());
			project.setProjectId(tmp.getProjectId());
			projectDTOs.add(project);
		}

		return projectDTOs;
	}

	@Override
	public List<UserDTO> retrieveTutors(long projectId) {
		EntityManager em = entityManager();
		List<Tutor> tutors = null;

		try {
			// Project project = em.find(Project.class, projectId);
			TypedQuery<Tutor> query = em
					.createQuery(
							"SELECT t FROM Project p JOIN p.tutors t WHERE p.projectId = ?1",
							Tutor.class);
			query.setParameter(1, projectId);
			tutors = query.getResultList();
		} finally {
			em.close();
		}

		List<UserDTO> userDTOs = new ArrayList<UserDTO>();
		for (Tutor tmp : tutors) {
			UserDTO tutor = new UserDTO();
			tutor.setUserId(tmp.getUserId());
			tutor.setUserName(tmp.getUserName());
			tutor.setEmail(tmp.getEmail());
			tutor.setEmailNotification(tmp.isEmailNotification());
			tutor.setFirstName(tmp.getFirstName());
			tutor.setLastName(tmp.getLastName());
			userDTOs.add(tutor);
		}

		return userDTOs;
	}

	@Override
	public Boolean deleteProject(long id) {
		EntityManager em = entityManager();
		EntityTransaction tx = em.getTransaction();

		Project project = em.find(Project.class, id);
		if (project == null) {
			return false;
		}
		try {
			tx.begin();
			em.remove(project);
			tx.commit();
			return true;
		} catch (Throwable t) {
			t.printStackTrace();
			tx.rollback();
			return false;
		} finally {
			em.close();
		}
	}

	@Override
	public ProjectDTO retrieveProject(long projectId) {
		EntityManager em = entityManager();
		Project project = em.find(Project.class, projectId);

		ProjectDTO projectDTO = new ProjectDTO();
		projectDTO.setTitle(project.getTitle());
		projectDTO.setType(project.getType());
		projectDTO.setDescription(project.getDescription());
		projectDTO.setProjectId(project.getProjectId());
		
		projectDTO.setTutors(retrieveTutors(projectId));

		return projectDTO;
	}

	@Override
	public Boolean updateProject(ProjectDTO projectDTO) {
		EntityManager em = entityManager();
		try {
			// Add tutors
			List<Tutor> tutors = new ArrayList<Tutor>();
			for (UserDTO tmp : projectDTO.getTutors()) {
				Tutor tutor = em.find(Tutor.class, tmp.getUserId());
				if (tutor != null) {
					tutors.add(tutor);
				}
			}
			Project project = em.find(Project.class, projectDTO.getProjectId());
			if (project != null) {
				em.getTransaction().begin();

				project.setTitle(projectDTO.getTitle());
				project.setDescription(projectDTO.getDescription());
				project.setType(projectDTO.getType());
				project.setTutors(tutors);

				em.getTransaction().commit();
			}

		} finally {
			em.close();
		}
		return true;
	}

}
